package com.googlecode.jphysics.optics;

import com.googlecode.jphysics.utils.Converters;
import com.googlecode.jphysics.utils.PhysicVariableException;
import com.googlecode.jphysics.utils.PhysicsConstants;

public class Refraction {
	private double initialRefractiveIndex = -1, finalRefractiveIndex = -1, incidenceAngle = -1, refractionAngle = -1;
	
	public void setInitialRefractiveIndex(double refractiveIndex) {
		initialRefractiveIndex = refractiveIndex;
	}
	
	public void setFinalRefractiveIndex(double refractiveIndex) {
		finalRefractiveIndex = refractiveIndex;
	}
	
	public void setIncidenceAngle(double angle) {
		incidenceAngle = angle;
	}
	
	public void setRefractionAngle(double angle) {
		refractionAngle = angle;
	}
	
	public double getInitialRefractiveIndex() throws PhysicVariableException {
		if (initialRefractiveIndex > -1) {
			return initialRefractiveIndex;
		}
		
		if (finalRefractiveIndex == -1) {
			throw new PhysicVariableException("Final refractive index is not set");
		} else if (refractionAngle == -1) {
			throw new PhysicVariableException("Refraction angle is not set");
		} else if (incidenceAngle == -1) {
			throw new PhysicVariableException("Incidence angle is not set");
		}
		
		return (finalRefractiveIndex*Math.sin(Converters.gradToRad(refractionAngle)))/Math.sin(incidenceAngle);
	}
	
	public double getFinalRefractiveIndex() throws PhysicVariableException {
		if (finalRefractiveIndex > -1) {
			return finalRefractiveIndex;
		}
		
		if (initialRefractiveIndex == -1) {
			throw new PhysicVariableException("Initial refractive index is not set");
		} else if (incidenceAngle == -1) {
			throw new PhysicVariableException("Incidence angle is not set");
		} else if (refractionAngle == -1) {
			throw new PhysicVariableException("Refraction angle is not set");
		}
		
		return (initialRefractiveIndex*Math.sin(Converters.gradToRad(incidenceAngle)))/Math.sin(refractionAngle);
	}
	
	public double getIncidenceAngle() throws PhysicVariableException {
		if (incidenceAngle > -1) {
			return incidenceAngle;
		}
		
		if (finalRefractiveIndex == -1) {
			throw new PhysicVariableException("Final refractive index is not set");
		} else if (incidenceAngle == -1) {
			throw new PhysicVariableException("Incidence angle is not set");
		} else if (initialRefractiveIndex == -1) {
			throw new PhysicVariableException("Initial refractive index is not set");
		}
		
		return Math.asin((finalRefractiveIndex*Math.sin(Converters.gradToRad(incidenceAngle)))/initialRefractiveIndex);
	}
	
	public double getRefractionAngle () throws PhysicVariableException {
		if (refractionAngle > -1) {
			return refractionAngle;
		}
		
		if (initialRefractiveIndex == -1) {
			throw new PhysicVariableException("Initial refractive index is not set");
		} else if (incidenceAngle == -1) {
			throw new PhysicVariableException("Incidence angle is not set");
		} else if (finalRefractiveIndex == -1) {
			throw new PhysicVariableException("Final refractive index is not set");
		}
		
		return Math.asin(Converters.gradToRad((initialRefractiveIndex*Math.sin(Converters.gradToRad(incidenceAngle)))/finalRefractiveIndex));
	}
	
	public double getIncidenceVelocity() throws PhysicVariableException {
		if (initialRefractiveIndex == -1) {
			throw new PhysicVariableException("Initial refractive index is not set");
		}
		
		return PhysicsConstants.C/initialRefractiveIndex;
	}
	
	public double getRefractionVelocity() throws PhysicVariableException {
		if (finalRefractiveIndex == -1) {
			throw new PhysicVariableException("Final refractive index is not set");
		}
		
		return PhysicsConstants.C/finalRefractiveIndex;
	}
}
